#pragma once

#include "fxcc/core/graph/common/MSDF.h"
#include "fxcc/json/Serializer.h"

namespace fxcc::graph::common
{
    struct MSDFMesh
    {
        std::shared_ptr<fxcc::graph::common::MeshJack> m_TextMesh;
    };

    struct MSDFResource
    {

        static std::string DefaultAltasMap()
        {
            return "ascii.png";
        }

        static std::string DefaultAltasJson()
        {
            return "ascii.json";
        }

        struct Desc
        {
            std::string m_AltasMapPath;
            std::string m_AltasJsonPath;

        } m_Desc;

        MSDFResource(const Desc& desc) :m_Desc(desc)
        {
            Init();
        }
        static bool HasFile(const std::string& _p)
        {
            return fs::exists(_p) && fs::is_regular_file(_p);
        }
        bool Init()
        {
            if (!HasFile(m_Desc.m_AltasJsonPath))
            {
                ztclog::info("no json config file %s", m_Desc.m_AltasJsonPath.c_str());
                return false;
            }
            if (!HasFile(m_Desc.m_AltasMapPath))
            {
                ztclog::info("no altas map file %s", m_Desc.m_AltasMapPath.c_str());
                return false;
            }

            fxcc::graph::common::ImageMipmap::Desc imageDesc;
            imageDesc.m_WICFlipY = true;
            imageDesc.m_wicHdr = false;
            imageDesc.m_wicPath = m_Desc.m_AltasMapPath;
            imageDesc.m_wicReq = 3;

            fxcc::graph::common::Texture2DJack::Desc texDesc(imageDesc);

            m_MSDFMap = fxcc::graph::common::GraphImpl::CreateTexture2D(texDesc);

            m_MSDFConfig = std::make_shared<MSDFConfig>();
            fxcc::json::Serializer jsonser;
            bool flag = jsonser.DecodePath<MSDFConfig>(m_Desc.m_AltasJsonPath, *m_MSDFConfig);

            return true;
        }
        static std::wstring UTF8ToWString(const std::string& utf8Str)
        {
            std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
            return converter.from_bytes(utf8Str);
        }
        MSDFMesh CreateTextMesh(const std::string& text , const int fontSize=17)
        {
            return CreateTextMesh(UTF8ToWString(text), fontSize);
        }
        MSDFMesh CreateTextMesh(const std::wstring& text, const int fontSize = 17)
        {
            MSDFMesh msdfMesh;

            if (text.empty())
            {
                return msdfMesh;
            }

            MSDFGeoData geoSubData;

            glm::vec2 _StartPos(0.0f, 0.0f);

            for (int _IndexSep = 0; _IndexSep < text.size(); _IndexSep++)
            {
                const wchar_t ch = text[_IndexSep];

                const auto& glyphInfo = m_MSDFConfig->getGlyph(ch);
                const auto& planeBound = glyphInfo.planeBounds;
                const auto& atlasBounds = glyphInfo.atlasBounds;

                MSDFGeoData sdfGeoData;
                sdfGeoData.indices32 =
                {
                    0, 1, 2,
                    0, 2, 3
                };

                sdfGeoData.vertices =
                {
                    glm::vec2(planeBound.left,  planeBound.bottom),
                    glm::vec2(planeBound.right, planeBound.bottom),
                    glm::vec2(planeBound.right, planeBound.top),
                    glm::vec2(planeBound.left,  planeBound.top),
                };

                sdfGeoData.texCoords =
                {
                    glm::vec2(atlasBounds.left,  atlasBounds.bottom),
                    glm::vec2(atlasBounds.right, atlasBounds.bottom),
                    glm::vec2(atlasBounds.right, atlasBounds.top),
                    glm::vec2(atlasBounds.left,  atlasBounds.top),
                };


                for (auto& index : sdfGeoData.indices32)
                {
                    index += 4 * _IndexSep;
                }
                for (auto& vertex : sdfGeoData.vertices)
                {
                    vertex += _StartPos;
                    
                    vertex *= fontSize;

                }

                for (auto& texCoords : sdfGeoData.texCoords)
                {
                    texCoords.x /= (float)m_MSDFConfig->altas.width;
                    texCoords.y /= (float)m_MSDFConfig->altas.height;
                }

                geoSubData.Add(sdfGeoData);

                float _Advanced = glyphInfo.advance;

                if (_IndexSep < text.size() - 1)
                {
                    int LeftUnicode = text[_IndexSep];
                    int RightUnicode = text[_IndexSep + 1];
                    auto kerningAdvance = m_MSDFConfig->GetKerningAdvance(LeftUnicode, RightUnicode);

                    _Advanced += kerningAdvance;
                    //ztclog::info("kerning %f", kerningAdvance);
                }

                _StartPos.x += _Advanced;
            }


            msdfMesh.m_TextMesh = fxcc::graph::common::GraphImpl::CreateMSDFMesh(geoSubData);
            return msdfMesh;
        }


        std::shared_ptr<fxcc::graph::common::Texture2DJack> m_MSDFMap;
        std::shared_ptr<MSDFConfig> m_MSDFConfig;


    };
};
